package com.hexingmo.dawn.lang;

import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;

/**
 *
 * @author He Xing Mo
 * @since 1.0
 */
public class GenericUtils {

    private GenericUtils() {
        throw new IllegalStateException("Static utility classes do not support instantiation");
    }

    /**
     * 检查给定的类型是否为泛型类型。
     *
     * <p>该方法用于判断一个 {@link Type} 对象是否代表泛型类型。泛型类型包括所有在编译时
     * 保留了泛型信息的类型，这些信息在运行时通常会被类型擦除。</p>
     *
     * <p><strong>支持的泛型类型：</strong></p>
     * <ul>
     *   <li><strong>ParameterizedType</strong>：参数化类型，如 {@code List<String>}、{@code Map<String, Integer>}</li>
     *   <li><strong>GenericArrayType</strong>：泛型数组类型，如 {@code List<String>[]}、{@code Map<String, Integer>[]}</li>
     *   <li><strong>WildcardType</strong>：通配符类型，如 {@code List<?>}、{@code List<? extends String>}</li>
     *   <li><strong>TypeVariable</strong>：类型变量，如泛型类中的 {@code T}、{@code E extends Number}</li>
     * </ul>
     *
     * <p><strong>非泛型类型示例：</strong></p>
     * <ul>
     *   <li><strong>Class</strong>：如 {@code String.class}、{@code List.class}（原始类型）</li>
     *   <li><strong>基本类型</strong>：如 {@code int.class}、{@code boolean.class}</li>
     *   <li><strong>数组类型</strong>：如 {@code String[].class}、{@code int[].class}</li>
     * </ul>
     *
     * <p><strong>使用示例：</strong></p>
     * <pre>{@code
     * // 检查字段的泛型类型
     * Field field = MyClass.class.getDeclaredField("stringList");
     * Type genericType = field.getGenericType();
     *
     * if (GenericUtils.isGenericType(genericType)) {
     *     System.out.println("字段是泛型类型");
     *     if (genericType instanceof ParameterizedType) {
     *         ParameterizedType paramType = (ParameterizedType) genericType;
     *         System.out.println("原始类型: " + paramType.getRawType());
     *         System.out.println("泛型参数: " + Arrays.toString(paramType.getActualTypeArguments()));
     *     }
     * } else {
     *     System.out.println("字段不是泛型类型");
     * }
     *
     * // 检查各种类型
     * System.out.println("List<String> 是泛型类型: " +
     *     GenericUtils.isGenericType(new TypeReference<List<String>>(){}.getType()));
     * System.out.println("String.class 是泛型类型: " +
     *     GenericUtils.isGenericType(String.class));
     * System.out.println("List 是泛型类型: " +
     *     GenericUtils.isGenericType(List.class));
     * }</pre>
     *
     * <p><strong>实际应用场景：</strong></p>
     * <ul>
     *   <li><strong>类型检查</strong>：在运行时验证对象是否符合泛型类型约束</li>
     *   <li><strong>序列化/反序列化</strong>：根据泛型类型信息正确解析数据</li>
     *   <li><strong>依赖注入</strong>：根据泛型类型创建相应的对象实例</li>
     *   <li><strong>ORM映射</strong>：将数据库结果映射到泛型集合字段</li>
     *   <li><strong>代码生成</strong>：生成类型安全的代码模板</li>
     *   <li><strong>数据验证</strong>：验证集合中的元素类型是否符合泛型约束</li>
     * </ul>
     *
     * <p><strong>注意事项：</strong></p>
     * <ul>
     *   <li>该方法依赖于编译时的泛型信息，如果使用原始类型则无法识别为泛型类型</li>
     *   <li>对于匿名内部类或局部类，可能无法获取完整的泛型信息</li>
     *   <li>该方法不会递归检查嵌套的泛型类型，只检查最外层的类型</li>
     *   <li>性能较好，适合在频繁调用的方法中使用</li>
     * </ul>
     *
     * <p><strong>性能特点：</strong></p>
     * <ul>
     *   <li>时间复杂度：O(1)，只进行类型检查</li>
     *   <li>空间复杂度：O(1)，不创建额外对象</li>
     *   <li>适合高频调用场景</li>
     * </ul>
     *
     * @param type 要检查的类型，不能为null
     * @return 如果是泛型类型返回true，否则返回false
     * @throws IllegalArgumentException 如果type参数为null
     * @see ParameterizedType
     * @see GenericArrayType
     * @see WildcardType
     * @see TypeVariable
     * @see Type
     */
    public static boolean isGenericType(Type type) {
        Assert.notNull(type, "Type must not be null");
        return type instanceof ParameterizedType
                || type instanceof GenericArrayType
                || type instanceof WildcardType
                || type instanceof TypeVariable;
    }

    /**
     * 检查字段是否为泛型类型字段。
     *
     * @param field 要检查的字段，不能为null
     * @return 如果字段是泛型类型返回true，否则返回false
     * @throws IllegalArgumentException 如果field参数为null
     */
    public static boolean isGenericTypeField(Field field) {
        return isGenericType(getGenericType(field));
    }

    /**
     * 检查字段是否不是泛型类型字段。
     *
     * @param field 要检查的字段，不能为null
     * @return 如果字段不是泛型类型返回true，否则返回false
     * @throws IllegalArgumentException 如果field参数为null
     */
    public static boolean isNotGenericTypeField(Field field) {
        return !isGenericType(getGenericType(field));
    }

    /**
     * 检查字段是否为参数化类型字段（如 List<String>）。
     *
     * @param field 要检查的字段，不能为null
     * @return 如果字段是参数化类型返回true，否则返回false
     * @throws IllegalArgumentException 如果field参数为null
     */
    public static boolean isParameterizedTypeField(Field field) {
        return getGenericType(field) instanceof ParameterizedType;
    }

    /**
     * 检查字段是否为泛型数组类型字段（如 List<String>[]）。
     *
     * @param field 要检查的字段，不能为null
     * @return 如果字段是泛型数组类型返回true，否则返回false
     * @throws IllegalArgumentException 如果field参数为null
     */
    public static boolean isGenericArrayTypeField(Field field) {
        return getGenericType(field) instanceof GenericArrayType;
    }

    /**
     * 检查字段是否为通配符类型字段（如 List<?>）。
     *
     * @param field 要检查的字段，不能为null
     * @return 如果字段是通配符类型返回true，否则返回false
     * @throws IllegalArgumentException 如果field参数为null
     */
    public static boolean isWildcardTypeField(Field field) {
        return containsWildcardType(getGenericType(field));
    }

    /**
     * 检查字段是否为类型变量字段（如泛型类中的 T）。
     *
     * @param field 要检查的字段，不能为null
     * @return 如果字段是类型变量返回true，否则返回false
     * @throws IllegalArgumentException 如果field参数为null
     */
    public static boolean isTypeVariableField(Field field) {
        return getGenericType(field) instanceof TypeVariable;
    }

    /**
     * 获取字段的参数化类型信息。
     *
     * <p>该方法用于获取字段的完整泛型类型信息，适用于需要了解字段具体泛型参数类型的场景。
     * 返回的 {@link ParameterizedType} 对象包含了原始类型和所有泛型参数信息。</p>
     *
     * <p><strong>适用场景：</strong></p>
     * <ul>
     *   <li><strong>List&lt;String&gt;</strong>：返回包含 List.class 原始类型和 String.class 泛型参数的 ParameterizedType</li>
     *   <li><strong>Map&lt;String, Integer&gt;</strong>：返回包含 Map.class 原始类型和 [String.class, Integer.class] 泛型参数的 ParameterizedType</li>
     *   <li><strong>Set&lt;List&lt;String&gt;&gt;</strong>：返回包含 Set.class 原始类型和嵌套泛型参数的 ParameterizedType</li>
     * </ul>
     *
     * <p><strong>返回类型说明：</strong></p>
     * <ul>
     *   <li><strong>ParameterizedType</strong>：如果字段是参数化类型，返回完整的泛型类型信息</li>
     *   <li><strong>null</strong>：如果字段不是参数化类型（如原始类型、基本类型、非泛型数组等）</li>
     * </ul>
     *
     * <p><strong>实际应用：</strong></p>
     * <ul>
     *   <li><strong>序列化/反序列化</strong>：根据泛型参数类型正确解析数据</li>
     *   <li><strong>数据验证</strong>：验证集合元素类型是否符合泛型约束</li>
     *   <li><strong>依赖注入</strong>：根据泛型类型创建相应的对象实例</li>
     *   <li><strong>ORM映射</strong>：将数据库结果映射到泛型集合字段</li>
     * </ul>
     *
     * @param field 要获取类型信息的字段，不能为null
     * @return 如果字段是参数化类型返回对应的ParameterizedType，否则返回null
     * @throws IllegalArgumentException 如果field参数为null
     * @see ParameterizedType
     * @see #isParameterizedTypeField(Field)
     */
    public static ParameterizedType getParameterizedTypeOfField(Field field) {
        return isParameterizedTypeField(field) ? (ParameterizedType) field.getGenericType() : null;
    }

    /**
     * 获取字段的泛型数组类型信息。
     *
     * <p>该方法用于获取字段的泛型数组类型信息，适用于需要了解数组组件泛型类型的场景。
     * 返回的 {@link GenericArrayType} 对象包含了数组组件的泛型类型信息。</p>
     *
     * <p><strong>适用场景：</strong></p>
     * <ul>
     *   <li><strong>List&lt;String&gt;[]</strong>：返回包含 List&lt;String&gt; 组件类型的 GenericArrayType</li>
     *   <li><strong>Map&lt;String, Integer&gt;[]</strong>：返回包含 Map&lt;String, Integer&gt; 组件类型的 GenericArrayType</li>
     *   <li><strong>Set&lt;List&lt;String&gt;&gt;[]</strong>：返回包含 Set&lt;List&lt;String&gt;&gt; 组件类型的 GenericArrayType</li>
     * </ul>
     *
     * <p><strong>返回类型说明：</strong></p>
     * <ul>
     *   <li><strong>GenericArrayType</strong>：如果字段是泛型数组类型，返回包含组件泛型信息的数组类型</li>
     *   <li><strong>null</strong>：如果字段不是泛型数组类型（如普通数组、参数化类型、基本类型等）</li>
     * </ul>
     *
     * @param field 要获取类型信息的字段，不能为null
     * @return 如果字段是泛型数组类型返回对应的GenericArrayType，否则返回null
     * @throws IllegalArgumentException 如果field参数为null
     * @see GenericArrayType
     * @see #isGenericArrayTypeField(Field)
     */
    public static GenericArrayType getGenericArrayTypeOfField(Field field) {
        return isGenericArrayTypeField(field) ? (GenericArrayType) field.getGenericType() : null;
    }

    /**
     * 获取字段的通配符类型信息。
     *
     * <p>该方法用于获取字段的通配符类型信息，适用于需要了解通配符边界约束的场景。
     * 返回的 {@link WildcardType} 对象包含了通配符的上界和下界信息。</p>
     *
     * <p><strong>适用场景：</strong></p>
     * <ul>
     *   <li><strong>List&lt;?&gt;</strong>：返回无界通配符类型，表示任意类型</li>
     *   <li><strong>List&lt;? extends String&gt;</strong>：返回有上界的通配符类型，表示 String 或其子类型</li>
     *   <li><strong>List&lt;? super Integer&gt;</strong>：返回有下界的通配符类型，表示 Integer 或其父类型</li>
     *   <li><strong>Map&lt;String, ?&gt;</strong>：返回部分通配符类型，键类型固定，值类型任意</li>
     * </ul>
     *
     * <p><strong>返回类型说明：</strong></p>
     * <ul>
     *   <li><strong>WildcardType</strong>：如果字段是通配符类型，返回包含边界信息的通配符类型</li>
     *   <li><strong>null</strong>：如果字段不是通配符类型（如具体类型、类型变量等）</li>
     * </ul>
     *
     *
     * @param field 要获取类型信息的字段，不能为null
     * @return 如果字段是通配符类型返回对应的WildcardType，否则返回null
     * @throws IllegalArgumentException 如果field参数为null
     * @see WildcardType
     * @see #isWildcardTypeField(Field)
     */
    public static WildcardType getWildcardTypeOfField(Field field) {
        return isWildcardTypeField(field) ? (WildcardType) field.getGenericType() : null;
    }

    /**
     * 获取字段的类型变量信息。
     *
     * <p>该方法用于获取字段的类型变量信息，适用于需要了解泛型类中类型参数定义的场景。
     * 返回的 {@link TypeVariable} 对象包含了类型变量的名称、边界等信息。</p>
     *
     * <p><strong>适用场景：</strong></p>
     * <ul>
     *   <li><strong>class Container&lt;T&gt; { private T item; }</strong>：返回表示类型参数 T 的 TypeVariable</li>
     *   <li><strong>class Box&lt;E extends Number&gt; { private E value; }</strong>：返回有上界约束的类型变量 E</li>
     *   <li><strong>class Pair&lt;K, V&gt; { private K key; private V value; }</strong>：返回多个类型变量 K 和 V</li>
     *   <li><strong>class Node&lt;T extends Comparable&lt;T&gt;&gt; { private T data; }</strong>：返回有复杂约束的类型变量</li>
     * </ul>
     *
     * <p><strong>返回类型说明：</strong></p>
     * <ul>
     *   <li><strong>TypeVariable</strong>：如果字段是类型变量，返回包含变量信息的类型变量</li>
     *   <li><strong>null</strong>：如果字段不是类型变量（如具体类型、通配符类型等）</li>
     * </ul>
     *
     *
     * @param field 要获取类型信息的字段，不能为null
     * @return 如果字段是类型变量返回对应的TypeVariable，否则返回null
     * @throws IllegalArgumentException 如果field参数为null
     * @see TypeVariable
     * @see #isTypeVariableField(Field)
     */
    public static TypeVariable<?> getTypeVariableOfField(Field field) {
        return isTypeVariableField(field) ? (TypeVariable<?>) field.getGenericType() : null;
    }

    public static boolean containsActualType(Field field , Class<?> actualType) {
        Class<?>[] actualTypes = getActualTypes(field);
        for (Class<?> at : actualTypes) {
            if (actualType.equals(at)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取字段的泛型类型信息。
     *
     * <p>该方法通过反射获取字段的完整类型信息，包括泛型参数。与 {@link Field#getType()} 不同，
     * 该方法能够保留泛型信息，返回 {@link ParameterizedType} 或 {@link GenericArrayType}。</p>
     *
     * <p><strong>类型擦除说明：</strong></p>
     * <ul>
     *   <li>Java在运行时擦除泛型类型信息，但该方法可以获取到编译时的泛型信息</li>
     *   <li>对于非泛型字段，返回null</li>
     *   <li>对于泛型字段，返回包含泛型参数的类型信息</li>
     * </ul>
     *
     * <p><strong>返回类型说明：</strong></p>
     * <ul>
     *   <li><strong>ParameterizedType</strong>：参数化类型，如 {@code List<String>}、{@code Map<String, Integer>}</li>
     *   <li><strong>GenericArrayType</strong>：泛型数组类型，如 {@code List<String>[]}</li>
     *   <li><strong>null</strong>：非泛型字段，如 {@code String}、{@code int}、{@code List}（原始类型）</li>
     * </ul>
     *
     * <p><strong>使用示例：</strong></p>
     * <pre>{@code
     * class ExampleClass {
     *     private List<String> stringList;           // 返回 ParameterizedType
     *     private Map<String, Integer> stringIntMap; // 返回 ParameterizedType
     *     private List<String>[] stringArray;        // 返回 GenericArrayType
     *     private String simpleString;               // 返回 null
     *     private List rawList;                      // 返回 null（原始类型）
     * }
     *
     * Field field = ExampleClass.class.getDeclaredField("stringList");
     * Type genericType = GenericUtils.getFieldGenericType(field);
     * if (genericType instanceof ParameterizedType) {
     *     ParameterizedType paramType = (ParameterizedType) genericType;
     *     Class<?> rawType = (Class<?>) paramType.getRawType();        // List.class
     *     Type[] typeArgs = paramType.getActualTypeArguments();       // [String.class]
     *     System.out.println("原始类型: " + rawType.getName());        // java.util.List
     *     System.out.println("泛型参数: " + typeArgs[0].getTypeName()); // java.lang.String
     * }
     * }</pre>
     *
     * <p><strong>实际应用场景：</strong></p>
     * <ul>
     *   <li><strong>序列化/反序列化</strong>：根据字段的泛型类型正确解析JSON、XML等数据</li>
     *   <li><strong>数据验证</strong>：验证集合中的元素类型是否符合泛型约束</li>
     *   <li><strong>依赖注入</strong>：根据泛型类型创建相应的对象实例</li>
     *   <li><strong>ORM映射</strong>：将数据库结果映射到泛型集合字段</li>
     *   <li><strong>代码生成</strong>：生成类型安全的代码模板</li>
     * </ul>
     *
     * <p><strong>注意事项：</strong></p>
     * <ul>
     *   <li>该方法依赖于编译时的泛型信息，如果使用原始类型则无法获取泛型信息</li>
     *   <li>对于匿名内部类或局部类，可能无法获取完整的泛型信息</li>
     *   <li>反射操作相对较慢，建议在初始化时调用并缓存结果</li>
     *   <li>返回的Type对象在JVM生命周期内有效，但不应长期持有引用</li>
     * </ul>
     *
     * <p><strong>性能考虑：</strong></p>
     * <ul>
     *   <li>首次调用会有反射开销，后续调用性能较好</li>
     *   <li>建议在应用启动时或类加载时预先获取并缓存泛型信息</li>
     *   <li>避免在频繁调用的方法中使用该方法</li>
     * </ul>
     *
     * <p><strong>相关方法：</strong></p>
     * <ul>
     *   <li>{@link #getActualTypes(Field)} - 获取字段的泛型参数类型</li>
     *   <li>{@link Field#getType()} - 获取字段的原始类型（不包含泛型信息）</li>
     *   <li>{@link Field#getGenericType()} - 获取字段的泛型类型（基础方法）</li>
     * </ul>
     *
     * @param field 要获取泛型类型信息的字段对象，不能为null
     * @return 字段的泛型类型信息：
     *         <ul>
     *           <li>如果是泛型字段，返回 {@link ParameterizedType} 或 {@link GenericArrayType}</li>
     *           <li>如果是非泛型字段，返回 {@code null}</li>
     *         </ul>
     * @throws IllegalArgumentException 如果field参数为null
     * @throws SecurityException 如果没有访问字段的权限
     * @see Field#getGenericType()
     * @see ParameterizedType
     * @see GenericArrayType
     * @see Type
     */
    public static Type getFieldGenericType(Field field) {

        // 获取字段的泛型类型
        Type genericType = getGenericType(field);

        // 检查是否为参数化类型（如 List<String>）
        if (genericType instanceof ParameterizedType) {
            return genericType;
        }

        // 检查是否为泛型数组类型（如 List<String>[]）
        if (genericType instanceof GenericArrayType) {
            return genericType;
        }

        // 非泛型字段返回null
        return null;
    }

    public static Class<?>[] getActualTypes(Field field) {
        return getActualTypes(getGenericType(field));
    }

    public static Class<?>[] getActualTypes(Type type) {
        if (type instanceof ParameterizedType) {
            ParameterizedType paramType = (ParameterizedType) type;
            Type[] actualTypeArguments = paramType.getActualTypeArguments();

            Class<?>[] result = new Class<?>[actualTypeArguments.length];
            for (int i = 0; i < actualTypeArguments.length; i++) {
                if (actualTypeArguments[i] instanceof Class) {
                    result[i] = (Class<?>) actualTypeArguments[i];
                } else if (actualTypeArguments[i] instanceof ParameterizedType) {
                    result[i] = (Class<?>) ((ParameterizedType) actualTypeArguments[i]).getRawType();
                }
            }
            return result;
        // 泛型数组类型
        } else if (type instanceof GenericArrayType) {
            GenericArrayType genericArrayType = (GenericArrayType) type;
            Type componentType = genericArrayType.getGenericComponentType();
            if (componentType instanceof ParameterizedType) {
                return getActualTypes(componentType);
            }
        }
        return new Class<?>[0];
    }

    /**
     * 检查给定的类型是否包含通配符类型。
     *
     * <p>该方法用于递归检查一个类型及其泛型参数中是否包含通配符类型（WildcardType）。
     * 通配符类型包括无界通配符 {@code ?}、有上界通配符 {@code ? extends T} 和有下界通配符 {@code ? super T}。</p>
     *
     * <p><strong>检查范围：</strong></p>
     * <ul>
     *   <li><strong>直接检查</strong>：检查类型本身是否为通配符类型</li>
     *   <li><strong>参数化类型检查</strong>：检查 {@code List<?>}、{@code Map<String, ?>} 等类型中的泛型参数</li>
     *   <li><strong>泛型数组检查</strong>：检查 {@code List<?>[]}、{@code Map<String, ?>[]} 等数组类型中的组件泛型参数</li>
     * </ul>
     *
     * <p><strong>适用场景示例：</strong></p>
     * <ul>
     *   <li><strong>List&lt;?&gt;</strong>：返回 true（直接包含通配符）</li>
     *   <li><strong>List&lt;? extends String&gt;</strong>：返回 true（包含有界通配符）</li>
     *   <li><strong>Map&lt;String, ?&gt;</strong>：返回 true（包含通配符作为值类型）</li>
     *   <li><strong>List&lt;?&gt;[]</strong>：返回 true（数组组件包含通配符）</li>
     *   <li><strong>List&lt;String&gt;</strong>：返回 false（不包含通配符）</li>
     *   <li><strong>String</strong>：返回 false（基本类型，不包含通配符）</li>
     * </ul>
     *
     * <p><strong>实际应用场景：</strong></p>
     * <ul>
     *   <li><strong>类型安全验证</strong>：在泛型操作中检查是否涉及通配符类型</li>
     *   <li><strong>序列化处理</strong>：根据是否包含通配符决定序列化策略</li>
     *   <li><strong>泛型方法设计</strong>：设计能够处理通配符类型的泛型方法</li>
     *   <li><strong>集合操作</strong>：在集合操作中识别通配符类型，确保类型安全</li>
     *   <li><strong>框架开发</strong>：开发支持通配符类型的框架和工具</li>
     * </ul>
     *
     * <p><strong>注意事项：</strong></p>
     * <ul>
     *   <li>该方法会递归检查嵌套的泛型类型，包括数组组件类型</li>
     *   <li>对于复杂的嵌套泛型类型，该方法能够正确识别其中的通配符</li>
     *   <li>性能较好，适合在需要频繁检查通配符类型的场景中使用</li>
     *   <li>该方法不会检查类型变量的边界约束，只关注通配符类型本身</li>
     * </ul>
     *
     * <p><strong>性能特点：</strong></p>
     * <ul>
     *   <li>时间复杂度：O(n)，其中 n 是泛型参数的数量</li>
     *   <li>空间复杂度：O(1)，不创建额外对象</li>
     *   <li>适合在类型检查频繁的场景中使用</li>
     * </ul>
     *
     * @param type 要检查的类型，不能为null
     * @return 如果类型包含通配符类型返回true，否则返回false
     * @throws IllegalArgumentException 如果type参数为null
     * @see WildcardType
     * @see ParameterizedType
     * @see GenericArrayType
     * @see #isWildcardTypeField(Field)
     */
    public static boolean containsWildcardType(Type type) {
        Assert.notNull(type, "Type must not be null");
        
        // 快速路径：直接检查是否为通配符类型
        if (type instanceof WildcardType) {
            return true;
        }
        
        // 检查参数化类型中的泛型参数
        if (type instanceof ParameterizedType) {
            return containsWildcardTypeInArguments(((ParameterizedType) type).getActualTypeArguments());
        }
        
        // 检查泛型数组类型中的组件类型
        if (type instanceof GenericArrayType) {
            return containsWildcardType(((GenericArrayType) type).getGenericComponentType());
        }
        
        return false;
    }
    
    /**
     * 检查类型参数数组中是否包含通配符类型。
     *
     * @param typeArguments 要检查的类型参数数组
     * @return 如果包含通配符类型返回true，否则返回false
     */
    private static boolean containsWildcardTypeInArguments(Type[] typeArguments) {
        for (Type typeArg : typeArguments) {
            if (containsWildcardType(typeArg)) {
                return true;
            }
        }
        return false;
    }

    public static Type getGenericType(Field field) {
        Assert.notNull(field, "Field parameter cannot be null");
        return field.getGenericType();
    }
}
